#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Playables;
#if SHADER_ANIMATED
using FSG.MeshAnimator.ShaderAnimated;
#endif

namespace GameDesigner
{
    [CanEditMultipleObjects]
    [CustomEditor(typeof(StateManager))]
    public class StateManagerEditor : StateMachineViewEditor
    {
        private StateManager self;
        protected override StateMachineView Self { get => self.support; set => self.support = (StateMachineMono)value; }

        private SerializedProperty _animationProperty;
        private SerializedProperty animationProperty => _animationProperty ??= SupportObject.FindProperty("animation");

        private SerializedProperty _animatorProperty;
        private SerializedProperty animatorProperty => _animatorProperty ??= SupportObject.FindProperty("animator");

        private SerializedProperty _meshAnimatorProperty;
        private SerializedProperty meshAnimatorProperty => _meshAnimatorProperty ??= SupportObject.FindProperty("meshAnimator");

        private SerializedProperty _directorProperty;
        private SerializedProperty directorProperty => _directorProperty ??= SupportObject.FindProperty("director");

        protected override void OnEnable()
        {
            self = target as StateManager;
            if (Self != null)
            {
                Self.GetClipNames(self.transform, clipNames);
                Self.controller.View = Self;
                if (string.IsNullOrEmpty(Self.editStateMachine.name))
                    Self.editStateMachine.name = "Base Layer";
                if (StateMachineWindow.support == null) //这个是假的“null”
                    StateMachineWindow.support = null;
                if (StateMachineWindow.support != Self)
                    StateMachineWindow.Init(Self);
            }
            if (stateTypes == null)
            {
                stateTypes = new List<Type>();
                AddBehaviourTypes(stateTypes, typeof(StateBehaviour));
            }
            if (actionTypes == null)
            {
                actionTypes = new List<Type>();
                AddBehaviourTypes(actionTypes, typeof(ActionBehaviour));
            }
            if (transitionTypes == null)
            {
                transitionTypes = new List<Type>();
                AddBehaviourTypes(transitionTypes, typeof(TransitionBehaviour));
            }
        }

        protected override void ResetPropertys()
        {
            base.ResetPropertys();
            _animationProperty = null;
            _animatorProperty = null;
            _directorProperty = null;
            _meshAnimatorProperty = null;
        }

        protected override void OpenWindow()
        {
            if (self.support == null) //是空的时候才能显示
                self.support = EditorGUILayout.ObjectField(PluginSetting.Language["State Machine Controller"], self.support, typeof(StateMachineMono), true) as StateMachineMono;
            if (GUILayout.Button(PluginSetting.Language["Open the state machine editor"], GUI.skin.GetStyle("LargeButtonMid"), GUILayout.ExpandWidth(true)))
            {
                if (Self != null)
                    Self.OnScriptReload();
                StateMachineWindow.ShowWindow(Self);
            }
        }

        protected override void OnDrawPreField()
        {
            EditorGUILayout.PropertyField(serializedObject.FindProperty("support"), new GUIContent(PluginSetting.Language["State Machine Controller"]));
            EditorGUILayout.PropertyField(serializedObject.FindProperty("initMode"), new GUIContent(PluginSetting.Language["initMode"]));
            var view = (StateMachineMono)Self;
            view.animMode = (AnimationMode)EditorGUILayout.EnumPopup(new GUIContent(PluginSetting.Language["Animation mode"], "animMode"), view.animMode);
            switch (view.animMode)
            {
                case AnimationMode.Animation:
                    EditorGUILayout.PropertyField(animationProperty, new GUIContent(PluginSetting.Language["Old animation"], "animation"));
                    break;
                case AnimationMode.Animator:
                    EditorGUILayout.PropertyField(animatorProperty, new GUIContent(PluginSetting.Language["New animation"], "animator"));
                    break;
                case AnimationMode.Timeline:
                    EditorGUILayout.PropertyField(directorProperty, new GUIContent(PluginSetting.Language["director animation"], "director"));
                    EditorGUILayout.PropertyField(animatorProperty, new GUIContent(PluginSetting.Language["New animation"], "animator"));
                    break;
#if SHADER_ANIMATED
                case AnimationMode.MeshAnimator:
                    EditorGUILayout.PropertyField(meshAnimatorProperty, new GUIContent(PluginSetting.Language["mesh Animated"], "meshAnimator"));
                    break;
#endif
            }
        }

        protected override void OnDrawActionPropertyField(StateAction action, SerializedProperty actionProperty)
        {
            var view = (StateMachineMono)Self;
            if (view.animMode == AnimationMode.Timeline)
            {
                var scRect = EditorGUILayout.GetControlRect(hasLabel: true, 18f, EditorStyles.popup);
                EditorGUI.BeginChangeCheck();
                var clipAssetProperty = actionProperty.FindPropertyRelative("clipAsset");
                EditorGUI.ObjectField(scRect, clipAssetProperty, typeof(PlayableAsset), new GUIContent(PluginSetting.Language["Playable Asset"], $"clipAsset -> length:{action.length}"));
                if (EditorGUI.EndChangeCheck())
                {
                    if (clipAssetProperty.objectReferenceValue is PlayableAsset clip)
                    {
                        action.clipName = clip.name;
                        action.length = (float)clip.duration;
                        SetDirty(Self);
                    }
                }
            }
        }

        protected override void OnPlayAnimation(StateAction action)
        {
            var view = (StateMachineMono)Self;
            EditorGUILayout.BeginHorizontal();
            var rect = EditorGUILayout.GetControlRect();
            if (GUI.Button(new Rect(rect.x + 45, rect.y, 30, rect.height), EditorGUIUtility.IconContent(animPlay ? "PauseButton" : "PlayButton")))
            {
                animPlay = !animPlay;
                playAction = action;
            }
            EditorGUI.BeginChangeCheck();
            action.animTime = GUI.HorizontalSlider(new Rect(rect.x + 75, rect.y, rect.width - 75, rect.height), action.animTime, 0f, action.animTimeMax);
            var normalizedTime = action.animTime / action.animTimeMax;
            EditorGUI.ProgressBar(new Rect(rect.x + 75, rect.y, rect.width - 75, rect.height), normalizedTime, $"动画进度:{action.animTime.ToString("f0")}");
            if (EditorGUI.EndChangeCheck())
            {
                animPlay = false;
                playAction = action;
                if (!EditorApplication.isPlaying)
                {
                    if (view.animMode == AnimationMode.Animator)
                        StateAction.SetBlendTreeParameter(action, view.animator);
                    PlayAnimation(view, action, normalizedTime);
                }
            }
            EditorGUILayout.EndHorizontal();
            if (animPlay && playAction == action && !EditorApplication.isPlaying)
            {
                if (view.animMode == AnimationMode.Animator)
                    StateAction.SetBlendTreeParameter(action, view.animator);
                elapsedTime += DeltaTime * action.state.animSpeed;
                normalizedTime = elapsedTime / action.length;
                action.animTime = normalizedTime / 1f * 100f;
                if (action.animTime >= action.animTimeMax)
                {
                    action.animTime = 0f;
                    elapsedTime = 0f;
                }
                PlayAnimation(view, action, normalizedTime);
            }
        }

        private void PlayAnimation(StateMachineMono view, StateAction action, float normalizedTime)
        {
            switch (view.animMode)
            {
                case AnimationMode.Animation:
                    {
                        var animation = view.animation;
                        var clip = animation[action.clipName].clip;
                        float time = clip.length * normalizedTime;
                        clip.SampleAnimation(view.gameObject, time);
                    }
                    break;
                case AnimationMode.Animator:
                    {
                        var animator = view.animator;
                        animator.Play(action.clipName, action.Layer.LayerIndex, normalizedTime);
                        animator.Update(0f);
                    }
                    break;
                case AnimationMode.Timeline:
                    {
                    }
                    break;
#if SHADER_ANIMATED
                case AnimationMode.MeshAnimator:
                    {
                    }
                    break;
#endif
            }
        }
    }
}
#endif